package org.zhongyin.Dao;

import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

import jxl.read.biff.BiffException;

import org.zhongyin.JPA.Entity.ArxModelResult;
import org.zhongyin.JPA.Entity.ArxModelRun;
import org.zhongyin.JPA.Entity.ArxModelType;
import org.zhongyin.JPA.Entity.PermanentHistoryData;
import org.zhongyin.Regression.Regression;
import org.zhongyin.Util.Utility;
import org.zhongyin.internal.core.ARXFirstWDProvider;
import org.zhongyin.internal.core.ARXSecondWDProvider;

import Jama.Matrix;

//import com.ibm.icu.impl.Utility;



public class LocalDBDaoImpl {
	private static final String PERSISTENCE_UNIT_NAME = "ARXBuffer";
	private static EntityManagerFactory factory;
	public static EntityManager em;
	
	public LocalDBDaoImpl(){
		factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
		em = factory.createEntityManager();
	}
	
	
	/**
	 * get arxmodel type according to the typeId
	 * @param typeId
	 * @return
	 */
	public ArxModelType getType(int typeId){
		Query query = em.createQuery("SELECT t FROM ArxModelType t where t.typeId = :typeId");
		query.setParameter("typeId", typeId);
		
		ArxModelType result = (ArxModelType) query.getSingleResult();
		
		System.out.println(result.getARX_name());
		return result;
	}
	
	/**
	 * get the latest running data according to the latest runId
	 * @return
	 */
	public ArxModelRun getRun(){
		Query query = em.createQuery("SELECT t FROM ArxModelRun t ORDER BY t.runId DESC");
//		query.setParameter("runId", runId);
		
		ArxModelRun result = (ArxModelRun) query.setFirstResult(0).setMaxResults(1).getSingleResult();
		
//		System.out.println(result.getRunId() + " " + result.getTimeUpdate() + " " + result.getArxModelType().getTypeId() + " " + result.getWeekDay());
		return result;
	}
	
	/**
	 * Insert arxModel run data into ARX_Model_Run table according to the typeId 
	 * @param typeId
	 * @return
	 * @throws ParseException
	 */
	public ArxModelRun addRunData(int typeId) throws ParseException{
		ArxModelRun run = new ArxModelRun();
		
//		run.setRunId(1);
		Date date = new Date();
		Date now = Utility.converToDateHH(date);
		
		run.setTimeUpdate(now);
		
		
		if(now.getDay() >= 1 && now.getDay() <=5){
			run.setWeekDay(1);
		}
		else{
			run.setWeekDay(0);
		}
		ArxModelType arxModelType = getType(typeId);
		run.setArxModelType(arxModelType);
		
		
		
		
		em.persist(run);
		
		return run;
	}
	
	
	/**
	 * Insert ArxModel result data into ARX_Model_Result table 
	 * @param type
	 * @param bIndex
	 * @param bValue
	 * @return
	 */
	public ArxModelResult addResultData(int type, int bIndex, double bValue, int hour){
		ArxModelRun arxModelRun = getRun();
		ArxModelResult result = new ArxModelResult();
		if(type == arxModelRun.getArxModelType().getTypeId()){
		
				
				result.setArxModelRun(arxModelRun);
				result.setBIndex(bIndex);
				result.setBValue(bValue);
				if(hour >=0 && hour <=23){
					result.setResultHour(hour);
				}else{
					throw new IllegalArgumentException("Hour should be between 0 and 23");
				}
				em.persist(result);
		}else{
			throw new IllegalArgumentException();
		}
		
		return result;
	}
	
	public List<Double> getResult(int typeId, int hour){
	
		Query queryFirst = em.createNativeQuery("SELECT b_value FROM arx_model_result " +
				"JOIN arx_model_run ON arx_model_result.result_run_id = arx_model_run.run_id " +
				"JOIN arx_model_type ON arx_model_run.run_type_id = arx_model_type.type_id " +
				"WHERE arx_model_type.type_id = ? AND arx_model_result.result_hour = ? " +
				"ORDER BY run_id desc " +
				"LIMIT 0, 26 ");
		Query querySecond = em.createNativeQuery("SELECT b_value FROM arx_model_result " +
				"JOIN arx_model_run ON arx_model_result.result_run_id = arx_model_run.run_id " +
				"JOIN arx_model_type ON arx_model_run.run_type_id = arx_model_type.type_id " +
				"WHERE arx_model_type.type_id = ? AND arx_model_result.result_hour = ? " +
				"ORDER BY run_id desc " +
				"LIMIT 0, 17 ");
		List<Double> result = new ArrayList<Double>();
		
		if(typeId!= 7){
			queryFirst.setParameter(1, typeId);
			queryFirst.setParameter(2, hour);
			result = queryFirst.getResultList();
		}else{
			querySecond.setParameter(1, typeId);
			querySecond.setParameter(2, hour);
			result = querySecond.getResultList();
		}
		
		
		
		System.out.println("ARXModeType" + typeId + " ,hour: " + hour);
		System.out.println("b: " + result);
		return result;
	}
	
	
	
	
	public static void main(String[] args) throws ParseException, BiffException, IOException{
		LocalDBDaoImpl l = new LocalDBDaoImpl();
//		l.addRunData(3);

		ARXFirstWDProvider test = new ARXFirstWDProvider();
		test.setHistdata();
		
		for(int i = 1; i <= 6; i++){
		
				
				test.setARXHistmodel(i, 0);
				
				
				
		//		
//				Utility.printArraySingleLine(test.getARXmodel_X());
//			
//				System.out.println(Arrays.toString(test.getARXmodel_Y()));
				
				double[][] array_X = test.getARXmodel_X();
				
				double[] array_Y = test.getARXmodel_Y();
				
				int length = array_Y.length;
			    
			    Matrix weight = Matrix.identity(length, length);
				
				Regression regression = new Regression();
				
				weight = regression.getIterWeight(array_Y, array_X, weight);
				
//				Utility.printArraySingleLine(weight.getArray());
				
				Matrix cofficient = regression.getWeightedCoefficient(array_Y, array_X, weight);
				
				em.getTransaction().begin();
				
				l.addRunData(i);
				
				for(int j = 0; j < cofficient.getArray().length; j++){
					
					
					l.addResultData(i, j, cofficient.get(j, 0), 1);
					
				}
				
				
				em.flush();
				em.getTransaction().commit();
				
				
				System.out.println("ARXModel("+i+"," + (i+1) + ", 24) b: " + Arrays.deepToString(cofficient.getArray()));
				}
		
		
		ARXSecondWDProvider second = new ARXSecondWDProvider();
		
		second.setHistdata();
		
		second.setARXHistmodel(0);
		//		
//		Utility.printArraySingleLine(second.getARXmodel_X());
//	
//		System.out.println(Arrays.toString(second.getARXmodel_Y()));
		
		double[][] array_X = second.getARXmodel_X();
		
		double[] array_Y = second.getARXmodel_Y();
		
		int length = array_Y.length;
	    
	    Matrix weight = Matrix.identity(length, length);
		
		Regression regression = new Regression();
		
		weight = regression.getIterWeight(array_Y, array_X, weight);
		
//				Utility.printArraySingleLine(weight.getArray());
		
		Matrix cofficient = regression.getWeightedCoefficient(array_Y, array_X, weight);
		
		em.getTransaction().begin();
		
		l.addRunData(7);
		
		for(int j = 0; j < cofficient.getArray().length; j++){
			
			
			l.addResultData(7, j, cofficient.get(j, 0), 1);
			
		}
		
		em.flush();
		em.getTransaction().commit();
		
		System.out.println("ARXModel(24, 168) b: " + Arrays.deepToString(cofficient.getArray()));
		
//	l.getResult(1);
		
		 
		
	}
}
